package inf3791.calendarsystem.others.components.calendar;

import inf3791.calendarsystem.shared.Appointment;
import inf3791.calendarsystem.shared.DaySpec;
import java.awt.Color;
import java.awt.Font;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableCellRenderer;

/**
 * Displays the current month with events
 *
 * @author Jonas Weber
 */
public class CalendarWidget extends JTable {

    private int month;
    private int year;
    private int selectedDay = -1;
    private DaySpec selDaySpec = null;

    public DaySpec getSelDaySpec() {
        return selDaySpec;
    }
    private Map<DaySpec, List<Appointment>> appointments;

    public Map<DaySpec, List<Appointment>> getAppointments() {
        return appointments;
    }

    private void fireSelectionChangedEvent() {
        int y = getSelectedColumn();
        int x = getSelectedRow();

        if (y == -1 || x == -1) {
            int ov = selectedDay;
            DaySpec ovo = selDaySpec;
            selectedDay = -1;
            selDaySpec = null;

            firePropertyChange("selectedDay", ov, -1);
            firePropertyChange("selDaySpec", ovo, null);
            return;
        }

        AppointmentWrapper aw = table[x][y];

        DayClickedEvent evt;
        if (aw == null) {
            //evt = new DayClickedEvent(CalendarWidget.this, 0, x, y, null);
            evt = null;
        } else {
            int ov = selectedDay;
            DaySpec ovo = selDaySpec;

            selectedDay = aw.dayspec.day;
            selDaySpec = aw.dayspec;

            evt = new DayClickedEvent(CalendarWidget.this, aw.dayspec, aw.d);
            firePropertyChange("selectedDay", ov, aw.dayspec.day);
            firePropertyChange("selDaySpec", ovo, selDaySpec);
        }

        for (DayClickedEvent.DayClickedListener l : clickedlisteners) {
            l.calendarDayClicked(evt);
        }
    }

    public void setAppointments(Map<DaySpec, List<Appointment>> appointments) {
        this.appointments = appointments;
        
        if (appointments == null) {
            return;
        }

        for (AppointmentWrapper[] aws : table) {
            for (AppointmentWrapper aw : aws) {
                aw.apps = appointments.get(aw.dayspec);
            }
        }
        ((CalendarTableModel) getModel()).doUpdateEvent();
    }

    /**
     * @return the month, 0 is January
     */
    public int getMonth() {
        return month;
    }

    /**
     * @param month the month to set, 0 is January
     */
    public void setMonth(int month) {
        this.month = month;
        calculateTable(month, year);
        setAppointments(appointments);
        fireSelectionChangedEvent();
    }

    /**
     * @return the year
     */
    public int getYear() {
        return year;
    }

    /**
     * @param year the year to set
     */
    public void setYear(int year) {
        this.year = year;
        calculateTable(month, year);
        setAppointments(appointments);
        fireSelectionChangedEvent();
    }

    /**
     * The currently selected day, or -1 if none selected
     */
    public int getSelectedDay() {
        return selectedDay;
    }
    private List<DayClickedEvent.DayClickedListener> clickedlisteners = new LinkedList<>();

    public void addDayClickedListener(DayClickedEvent.DayClickedListener listener) {
        clickedlisteners.add(listener);
    }

    public void removeDayClickedListener(DayClickedEvent.DayClickedListener listener) {
        clickedlisteners.remove(listener);
    }
    
    AppointmentWrapper[][] table = new AppointmentWrapper[][]{
        {null, null, null, null, null, null, null},
        {null, null, null, null, null, null, null},
        {null, null, null, null, null, null, null},
        {null, null, null, null, null, null, null},
        {null, null, null, null, null, null, null},
        {null, null, null, null, null, null, null}
    };

    final void calculateTable(int month, int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.YEAR, year /*- 1900*/);
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
            calendar.add(Calendar.DAY_OF_YEAR, -1);
        }

        for (int y = 0; y < 6; y++) {
            for (int x = 0; x < 7; x++) {
                AppointmentWrapper aw = new AppointmentWrapper(null,
                        calendar.get(Calendar.MONTH) + 1 == month,
                        new DaySpec(calendar.get(Calendar.DAY_OF_MONTH),
                        calendar.get(Calendar.MONTH) + 1,
                        calendar.get(Calendar.YEAR)),
                        calendar.getTime());

                calendar.add(Calendar.DATE, 1);
                setValueAt(aw, y, x);
            }
        }
    }

    public CalendarWidget() {
        setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 50));

        setModel(new CalendarTableModel(table));

        setMonth(0);
        setYear(2012);

        setRowMargin(0);
        setRowHeight(50);

        setBorder(null);



        getTableHeader().setBackground(Color.WHITE);
        getTableHeader().setReorderingAllowed(false);
        getTableHeader().setResizingAllowed(false);
        setGridColor(Color.WHITE);

        getTableHeader().setDefaultRenderer(new DayRenderer());

        ListSelectionListener lsl = new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent lse) {
                fireSelectionChangedEvent();
            }
        };

        getSelectionModel().addListSelectionListener(lsl);
        getColumnModel().getSelectionModel().addListSelectionListener(lsl);

        setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        //setRowSelectionAllowed(false);
        setCellSelectionEnabled(true);
    }

    @Override
    public TableCellRenderer getCellRenderer(int row, int column) {
        return new AppointmentRenderer();
    }
}
